package tum0r.controller;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.stage.DirectoryChooser;
import javafx.stage.FileChooser;
import tum0r.model.Resource;
import tum0r.model.ResourceContent;
import tum0r.model.ResourceTableModel;
import tum0r.model.StaticResource;
import tum0r.util.DealWithSearch;
import tum0r.util.Log;
import tum0r.util.PageModel;
import tum0r.util.StringUtils;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.UUID;

/**
 * 工程: ResourcesDatabase<br>
 * 包: tum0r.controller<br>
 * 创建者: tum0r<br>
 * 创建时间: 2020/10/4 08:08<br>
 * <br>
 */
public class MainViewController {
    @FXML
    private Label log;
    @FXML
    private TextField host;
    @FXML
    private TextField port;
    @FXML
    private TextField username;
    @FXML
    private PasswordField password;
    @FXML
    private Button connection;
    @FXML
    private Button close;
    @FXML
    private TextField directoryPath;
    @FXML
    private Button createLabelsButton;
    @FXML
    private TextField labelPath;
    @FXML
    private Button writeResourcesButton;
    @FXML
    private TextArea searchText;
    @FXML
    private Button searchButton;
    @FXML
    private Button extraButton;
    @FXML
    private ComboBox<String> pageSelect;
    @FXML
    private Button jumpButton;
    @FXML
    private Label pageLog;
    @FXML
    private TableView<ResourceTableModel> resultTable;

    public void connectionDatabase() {
        String host = this.host.getText();
        int port = 3306;
        try {
            port = Integer.parseInt(this.port.getText());
        } catch (Exception e) {
            this.port.setText(String.valueOf(port));
        }
        String username = this.username.getText();
        String password = this.password.getText();
        Log log = new Log(this.log);
        if (StaticResource.sql.open(host, port, "", username, password)) {
            this.host.setDisable(true);
            this.port.setDisable(true);
            this.username.setDisable(true);
            this.password.setDisable(true);
            this.connection.setDisable(true);
            this.close.setDisable(false);
            if (this.labelPath.getText().trim().length() != 0) {
                this.writeResourcesButton.setDisable(false);
            }
            this.searchText.setDisable(false);
            this.searchButton.setDisable(false);
            if (this.directoryPath.getText().trim().length() != 0) {
                this.extraButton.setDisable(false);
            }
            this.pageSelect.setDisable(false);
            this.jumpButton.setDisable(false);

            StaticResource.sql.initDatabase(StaticResource.INNIT_DATABASE[0]);
            StaticResource.sql.close();

            StaticResource.sql.open(host, port, StaticResource.DATABASE_NAME, username, password);
            for (int i = 1; i < StaticResource.INNIT_DATABASE.length; i++) {
                StaticResource.sql.initDatabase(StaticResource.INNIT_DATABASE[i]);
            }

            TableColumn tableColumn1 = new TableColumn("ID");
            tableColumn1.setCellValueFactory(new PropertyValueFactory<>("ID"));
            tableColumn1.setEditable(true);
            TableColumn tableColumn2 = new TableColumn("名称");
            tableColumn2.setCellValueFactory(new PropertyValueFactory<>("Name"));
            TableColumn tableColumn3 = new TableColumn("类型");
            tableColumn3.setCellValueFactory(new PropertyValueFactory<>("Type"));
            TableColumn tableColumn4 = new TableColumn("标签");
            tableColumn4.setCellValueFactory(new PropertyValueFactory<>("Label"));
            TableColumn tableColumn5 = new TableColumn("创建时间");
            tableColumn5.setCellValueFactory(new PropertyValueFactory<>("CreateTime"));
            TableColumn tableColumn6 = new TableColumn("上次访问时间");
            tableColumn6.setCellValueFactory(new PropertyValueFactory<>("LastAccessTime"));
            TableColumn tableColumn7 = new TableColumn("大小");
            tableColumn7.setCellValueFactory(new PropertyValueFactory<>("Size"));

            this.resultTable.getColumns().addAll(tableColumn1,
                    tableColumn2,
                    tableColumn3,
                    tableColumn4,
                    tableColumn5,
                    tableColumn6,
                    tableColumn7);
            this.resultTable.setEditable(true);
            tableColumn1.setCellFactory(TextFieldTableCell.<ResourceTableModel>forTableColumn());

            searchResources();

            log.displayLog("数据库 " + StaticResource.DATABASE_NAME + " 连接成功");
        } else {
            log.displayLog("数据库连接失败，检查数据库是否开启和相关参数");
        }
    }

    public void closeDatabase() {
        Log log = new Log(this.log);
        if (StaticResource.sql.close()) {
            this.host.setDisable(false);
            this.port.setDisable(false);
            this.username.setDisable(false);
            this.password.setDisable(false);
            this.connection.setDisable(false);
            this.close.setDisable(true);
            this.writeResourcesButton.setDisable(true);
            this.searchText.setDisable(true);
            this.searchButton.setDisable(true);
            this.extraButton.setDisable(true);
            this.pageSelect.setDisable(true);
            this.jumpButton.setDisable(true);
            this.pageLog.setText("请先连接数据库");

            log.displayLog("数据库断开成功");
        } else {
            log.displayLog("数据库断开失败，请重试");
        }
    }

    public void openDirectory() {
        Log log = new Log(this.log);
        DirectoryChooser directoryChooser = new DirectoryChooser();
        directoryChooser.setTitle("选择文件夹");
        File file = directoryChooser.showDialog(null);
        if (file != null && file.exists() && file.isDirectory() && file.canRead() && file.canWrite()) {
            directoryPath.setText(file.getAbsolutePath());
            createLabelsButton.setDisable(false);
            if (this.connection.isDisable()) {
                this.extraButton.setDisable(false);
            }
            log.displayLog("输入/输出文件夹选择成功，路径: " + file.getAbsolutePath());
        } else {
            log.displayLog("请选择输入/输出文件夹");
        }
    }

    public int readFiles(StringBuilder labels, File dir) {
        int result = 0;
        if (labels != null && dir != null && dir.exists() && dir.isDirectory() && dir.canRead() && dir.canWrite()) {
            File[] files = dir.listFiles();
            if (files != null) {
                for (File f : files) {
                    if (f != null && !f.isHidden() && f.canRead() && f.canWrite()) {
                        if (f.isFile()) {
                            labels.append(StaticResource.LABEL_FILE);
                            labels.append(f.getAbsolutePath());
                            labels.append(System.lineSeparator());
                            labels.append(StaticResource.LABEL_MARK);
                            labels.append(System.lineSeparator());
                            result++;
                        } else if (f.isDirectory()) {
                            result += readFiles(labels, f);
                        }
                    }
                }
            }
        }
        return result;
    }

    public void createLabels() {
        Log log = new Log(this.log);
        FileChooser fileChooser = new FileChooser();
        fileChooser.setTitle("创建标签文件");
        fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("文本文件", "*.txt"));
        File labelFile = fileChooser.showSaveDialog(null);
        if (labelFile != null) {
            boolean create = true;
            if (!labelFile.exists()) {
                try {
                    create = labelFile.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (create) {
                String dirPath = directoryPath.getText();
                if (!StringUtils.isNullOrOnlyWhiteSpace(dirPath)) {
                    StringBuilder labels = new StringBuilder();
                    File dir = new File(directoryPath.getText());
                    int count = readFiles(labels, dir);
                    try {
                        OutputStream fileOutputStream = new FileOutputStream(labelFile);
                        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);
                        BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
                        bufferedWriter.write(labels.toString().trim());
                        bufferedWriter.flush();
                        bufferedWriter.close();
                        outputStreamWriter.close();
                        fileOutputStream.close();
                        labelPath.setText(labelFile.getAbsolutePath());
                        if (this.connection.isDisable()) {
                            this.writeResourcesButton.setDisable(false);
                        }
                        log.displayLog("创建标签文件完成，共找到 " + count + " 个文件，标签文件路径: " + labelFile.getAbsolutePath());
                    } catch (IOException e) {
                        log.displayLog("无法创建标签文件，请检查标签文件所在目录权限");
                    }
                } else {
                    log.displayLog("无法创建标签文件，请选择读取目录");
                }
            } else {
                log.displayLog("无法创建标签文件，请检查标签文件所在目录权限");
            }
        } else {
            log.displayLog("请选择要写入的标签文本路径");
        }
    }

    public void openLabels() {
        Log log = new Log(this.log);
        FileChooser fileChooser = new FileChooser();
        fileChooser.setTitle("选择标签文件");
        fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("文本文件", "*.txt"));
        File labelFile = fileChooser.showOpenDialog(null);
        if (labelFile != null) {
            if (labelFile.exists() && labelFile.isFile() && labelFile.canRead()) {
                labelPath.setText(labelFile.getAbsolutePath());
                if (this.connection.isDisable()) {
                    this.writeResourcesButton.setDisable(false);
                }
                log.displayLog("选择标签文件成功，路径: " + labelFile.getAbsolutePath());
            } else {
                log.displayLog("无法选择标签文件，请检查标签文件权限");
            }
        }
    }

    public void writeResources() {
        Log log = new Log(this.log);
        String labelsPath = this.labelPath.getText();
        if (!StringUtils.isNullOrOnlyWhiteSpace(labelsPath)) {
            try {
                FileInputStream labelsFile = new FileInputStream(labelsPath);
                InputStreamReader inputStreamReader = new InputStreamReader(labelsFile);
                BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
                LinkedList<String> data = new LinkedList<>();
                String line;
                while ((line = bufferedReader.readLine()) != null) {
                    data.add(line);
                }
                bufferedReader.close();
                inputStreamReader.close();
                labelsFile.close();

                int size = data.size() - 1;
                for (int i = 0; i <= size; i++) {
                    String temp = data.get(i);
                    String temp2 = null;
                    if (i < size) {
                        temp2 = data.get(i + 1);
                    }
                    File file = null;
                    String label = "";
                    if (!StringUtils.isNullOrOnlyWhiteSpace(temp)) {
                        if (temp.startsWith(StaticResource.LABEL_FILE)) {
                            file = new File(temp.replace(StaticResource.LABEL_FILE, "").trim());
                        }
                    }

                    if (!StringUtils.isNullOrOnlyWhiteSpace(temp2)) {
                        if (temp2.startsWith(StaticResource.LABEL_MARK)) {
                            label = temp2.replace(StaticResource.LABEL_MARK, "").trim();
                        }
                    }

                    if (file != null) {
                        Resource resource = new Resource();
                        resource.setResource(file);
                        boolean flag = false;
                        if (resource.resourceContent != null && resource.resourceContent.size() != 0) {
                            resource.setNewID();
                            resource.Label = label;
                            int state = StaticResource.sql.update("INSERT INTO " + StaticResource.FILE_INFORMATION_TABLE + " VALUES(@p0, @p1, @p2, @p3, @p4, @p5, @p6)",
                                    resource.ID, resource.Name, resource.Type, resource.Label, resource.CreateTime, resource.LastAccessTime, resource.Size);
                            if (state > 0) {
                                for (ResourceContent content : resource.resourceContent) {
                                    String contentID = StaticResource.sql.selectValue("SELECT ID FROM " + StaticResource.FILE_CONTENT_TABLE + " WHERE Fingerprint = @p0", String.class, content.Fingerprint);
                                    String relateID = UUID.randomUUID().toString().replace("-", "");
                                    if (StringUtils.isNullOrOnlyWhiteSpace(contentID)) {
                                        state = StaticResource.sql.update("INSERT INTO " + StaticResource.FILE_CONTENT_TABLE + " VALUE(@p0, @p1, @p2)", content.ID, content.Fingerprint, content.Content);
                                        if (state > 0) {
                                            contentID = content.ID;
                                        }
                                    } else {
                                        state = 1;
                                    }

                                    if (state > 0) {
                                        state = StaticResource.sql.update("INSERT INTO " + StaticResource.FILE_RELATE_TABLE + " VALUE(@p0, @p1, @p2, @p3)", relateID, content.Index, resource.ID, contentID);
                                        if (state > 0) {
                                            flag = true;
                                        }
                                    }
                                }
                            }
                        }
                        log.displayLog("写入资源" + file.getName() + (flag ? "成功" : "失败"));
                        if (flag) {
                            file.delete();
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
                log.displayLog("标签文件读取失败，请检查文件是否存在及其权限");
            }
        } else {
            log.displayLog("请选选择标签路径");
        }
    }

    public void search(int index) {
        DealWithSearch dealWithSearch = new DealWithSearch();
        LinkedList<Object> sql = dealWithSearch.dealWith(searchText.getText());
        StaticResource.COMMAND.clear();
        StaticResource.COMMAND.addAll(sql);

        String command = (String) sql.getFirst();
        sql.removeFirst();
        PageModel<Resource> resourcePageModel = StaticResource.sql.selectPage(index, Resource.class, command, sql.toArray());
        if (resourcePageModel != null && resourcePageModel.model != null) {
            ObservableList<ResourceTableModel> data = FXCollections.observableArrayList();
            for (Resource resource : resourcePageModel.model) {
                if (resource != null) {
                    resource.convertSize();
                    data.add(new ResourceTableModel(resource));
                }
            }
            this.resultTable.setItems(data);
        }

        ObservableList<String> pageData = FXCollections.observableArrayList();
        for (int i = 1; i <= resourcePageModel.allPage; i++) {
            pageData.add("第 " + i + " 页");
        }
        if (pageData.size() == 0) {
            pageData.add("第 1 页");
        }
        this.pageSelect.setValue(pageData.get(index));
        this.pageSelect.setItems(pageData);
        this.pageSelect.setVisibleRowCount(5);
        this.pageLog.setText("共计 " + resourcePageModel.count + " 条数据");
    }

    public void searchResources() {
        search(0);
    }

    public void jumpPage() {
        int index = Integer.parseInt(this.pageSelect.getValue().replace("第", "").replace("页", "").trim()) - 1;
        search(index);
    }
}
